package com.jiangyg.mall.db.hibernate;

import com.jiangyg.mall.db.hibernate.transform.AliasToBeanResultTransformer;
import com.jiangyg.mall.db.hibernate.transform.AliasToCamelCaseMapResultTransformer;
import org.hibernate.HibernateException;
import org.hibernate.Session;
import org.hibernate.engine.query.spi.ParamLocationRecognizer;
import org.hibernate.engine.query.spi.ParameterParser;
import org.hibernate.query.NativeQuery;
import org.hibernate.query.internal.NativeQueryImpl;

import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Set;

/**
 * 类描述：hibernate工具类
 *
 * @author jiangyg
 * @version 4.0
 * @date 2021-01-05
 */
public class HibernateSupport {

    /**
     * 功能描述：查询list<map>结果集
     *
     * @param queryString 查询SQL字符串
     * @param searchModel 查询模型
     * @param session     指定session
     * @return 结果集
     */
    public static List<Map<String, Object>> queryListMapByQueryString(final String queryString, final Object searchModel, Session session) {
        final NativeQueryImpl query = session.createSQLQuery(queryString).unwrap(NativeQueryImpl.class);
        HibernateSupport.setProperties(query, searchModel, session);
        query.setResultTransformer(AliasToCamelCaseMapResultTransformer.INSTANCE);
        return query.list();
    }

    /**
     * 功能描述：查询list<T>结果集
     *
     * @param queryString 查询SQL字符串
     * @param searchModel 查询模型
     * @param clazz       结果集clazz
     * @param session     指定session
     * @return 结果集
     */
    public static <T> List<T> queryListByQueryString(final String queryString, final Object searchModel, Class<T> clazz, Session session) {
        final NativeQueryImpl query = session.createSQLQuery(queryString).unwrap(NativeQueryImpl.class);
        HibernateSupport.setProperties(query, searchModel, session);
        query.setResultTransformer(new AliasToBeanResultTransformer<>(clazz));
        return query.list();
    }

    /**
     * 功能描述：统计总数
     *
     * @param queryString SQL字符串
     * @param searchModel 查询模型
     * @param session     指定session
     * @return 结果集
     */
    public static Integer queryCountByQueryString(final String queryString, final Object searchModel, Session session) {
        final NativeQueryImpl query = session.createSQLQuery(queryString).unwrap(NativeQueryImpl.class);
        HibernateSupport.setProperties(query, searchModel, session);
        return Integer.parseInt(query.list().get(0).toString());
    }

    /**
     * 功能描述：分页查询list<T>结果集
     *
     * @param queryString 查询SQL字符串
     * @param searchModel 查询模型
     * @param pageNum     页码
     * @param pageSize    页大小
     * @param session     指定session
     * @return 结果集
     */
    public static <T> List<T> queryListByQueryString(final String queryString, final Object searchModel, Class<T> clazz, int pageNum, int pageSize, Session session) {
        final NativeQueryImpl query = session.createSQLQuery(queryString).unwrap(NativeQueryImpl.class);
        HibernateSupport.setProperties(query, searchModel, session);
        query.setResultTransformer(new AliasToBeanResultTransformer<>(clazz));
        query.setFirstResult((pageNum - 1) * pageSize);
        query.setMaxResults(pageSize);
        return query.list();
    }

    /**
     * 功能描述：分页查询list<map>结果集
     *
     * @param queryString 查询SQL字符串
     * @param searchModel 查询模型
     * @param pageNum     页码
     * @param pageSize    页大小
     * @param session     指定session
     * @return 结果集
     */
    public static List<Map<String, Object>> queryListMapByQueryString(final String queryString, final Object searchModel, int pageNum, int pageSize, Session session) {
        final NativeQueryImpl query = session.createSQLQuery(queryString).unwrap(NativeQueryImpl.class);
        HibernateSupport.setProperties(query, searchModel, session);
        query.setResultTransformer(AliasToCamelCaseMapResultTransformer.INSTANCE);
        query.setFirstResult((pageNum - 1) * pageSize);
        query.setMaxResults(pageSize);
        return query.list();
    }

    /**
     * 功能描述：查询list<T>结果集
     *
     * @param queryString 查询SQL字符串
     * @param searchModel 查询模型
     * @param maxResults  最大结果集
     * @param session     指定session
     * @return 结果集
     */
    public static <T> List<T> queryListByQueryString(final String queryString, final Object searchModel, int maxResults, Class<T> clazz, Session session) {
        final NativeQueryImpl query = session.createSQLQuery(queryString).unwrap(NativeQueryImpl.class);
        HibernateSupport.setProperties(query, searchModel, session);
        query.setResultTransformer(new AliasToBeanResultTransformer<>(clazz));
        query.setMaxResults(maxResults);
        return query.list();
    }

    /**
     * 功能描述：查询list<map>结果集
     *
     * @param queryString 查询SQL字符串
     * @param searchModel 查询模型
     * @param maxResults  最大结果集
     * @param session     指定session
     * @return 结果集
     */
    public static List<Map<String, Object>> queryListMapByQueryString(final String queryString, final Object searchModel, int maxResults, Session session) {
        final NativeQueryImpl query = session.createSQLQuery(queryString).unwrap(NativeQueryImpl.class);
        HibernateSupport.setProperties(query, searchModel, session);
        query.setResultTransformer(AliasToCamelCaseMapResultTransformer.INSTANCE);
        query.setMaxResults(maxResults);
        return query.list();
    }

    /**
     * 功能描述：执行SQL
     *
     * @param excuteSQL 执行SQL字符串
     * @param dto       数据DTO
     * @param session   指定session
     * @return 执行条数
     */
    public static int executeUpdateString(final String excuteSQL, final Object dto, Session session) {
        final NativeQueryImpl query = session.createSQLQuery(excuteSQL).unwrap(NativeQueryImpl.class);
        HibernateSupport.setProperties(query, dto, session);
        return query.executeUpdate();
    }

    /**
     * 功能描述：设置查询参数
     *
     * @param query       查询接口
     * @param searchModel 查询模型
     */
    public static void setProperties(final NativeQuery query, final Object searchModel, final Session session) throws HibernateException {
        if (searchModel == null) {
            return;
        }
        // 如果查询模型为集合（不能设置不存在的参数，否则报错）
        if (searchModel instanceof Map) {
            // 解析查询SQL中的参数
            final int jdbcStyleOrdinalCountBase = session.getSessionFactory().getSessionFactoryOptions().jdbcStyleParamsZeroBased() ? 0 : 1;
            final ParamLocationRecognizer recognizer = new ParamLocationRecognizer(jdbcStyleOrdinalCountBase);
            ParameterParser.parse(query.getQueryString(), recognizer);
            Set<String> namedParams = recognizer.getNamedParameterDescriptionMap().keySet();
            // 从searchModel获取查询参数
            Map<String, ?> searchModelMap = (Map<String, ?>) searchModel;
            for (String namedParam : namedParams) {
                Object value = searchModelMap.get(namedParam);
                if (value == null) {
                    throw new HibernateException("执行查询SQL报错：未获取到参数[" + namedParam + "]的值！");
                }
                if (value.getClass().isArray()) {
                    query.setParameterList(namedParam, (Object[]) value);
                    continue;
                }
                if (value instanceof Collection) {
                    query.setParameterList(namedParam, (Collection<?>) value);
                    continue;
                }
                query.setParameter(namedParam, value);
            }
            return;
        }
        // 默认的设置参数方法
        query.setProperties(searchModel);
    }

}
